
/*
    Software License

    Copyright (C) 2021-05-24  Xoronos

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, version 3.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

/*
    Liabilities

    The software is provided "AS IS" without any warranty of any kind, either expressed,
    implied, or statutory, including, but not limited to, any warranty that the software
    will conform to specifications, any implied warranties of merchantability, fitness
    for a particular purpose, and freedom from infringement, and any warranty that the
    documentation will conform to the software, or any warranty that the software will
    be error free.

    In no event shall Xoronos be liable for any damages, including, but not limited to,
    direct, indirect, special or consequential damages, arising out of, resulting from,
    or in any way connected with this software, whether or not based upon warranty,
    contract, tort, or otherwise, whether or not injury was sustained by persons or
    property or otherwise, and whether or not loss was sustained from, or arose out of
    the results of, or use of, the software or services provided hereunder.

    To request the provided software under a different license you can contact us at
    support@xoronos.com
*/

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <float.h>
#include <stdint.h>
#include <limits.h>

#include "lexscript.h"
#include "lexer_main.h"
#include "lexhelp.h"
#include "lexcheck.h"
#include "lexcheck_backend.h"
#include "lexexample.h"
#include "lexexample_backend.h"

xlex_log_t lexer_log;

int initialize_log( uint8_t lexer_log_en, int write_append, int logfile_set, char log_path[XRNL_MAX_STR_SIZE]
 )
{
    lexer_log.en = lexer_log_en;
    if ( logfile_set == 1 ) {
        if ( write_append == 0 ) {
            lexer_log.fp = fopen( log_path, "w" );
        } else {
            lexer_log.fp = fopen( log_path, "a" );
        }

        if ( lexer_log.fp == NULL ) {
            lexer_log.fp = stdout;
            snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                      "\nlexer error: io error while opening %s\n", log_path );
            XLEX_PRINT(  );
            return LEXERROR;
        }

    }

    return LEXFORWARD;
}

int lexer_main( int argc, char *argv[]
 )
{

    char *all_args_uniq[] = XSTR_ALL_ARGS_UNIQ;
    char *all_args[] = XSTR_ALL_ARGS;
    char buffer[XRNL_MAX_STR_SIZE];
    char log_path[XRNL_MAX_STR_SIZE];
    int i, j, logfile_set, write_append, ret, recognized, current_command, current_option_or_command,
        arg_type, commandarg, rndflag, log_file;
    uint8_t lexer_log_en;

    uint64_t dc_disparity_err_th, dc_disparity_war_th, dc_running_err_th, dc_running_war_th;
    uint64_t ec_disparity_err_th, ec_disparity_war_th, ec_running_err_th, ec_running_war_th;
    uint64_t start_timestamp, end_timestamp, state_size, architecture;
    uint64_t len;

    int command_options_vector[XLEN_ALL_ARGS];
    float numberf;
    uint64_t numberi;
    int errno;
    char *endptr;

    current_command = 0;
    arg_type = XARG_NULL;

    // default used if lexer main
    lexer_log.en = 1;
    lexer_log.fp = stdout;

    if ( argc == 1 ) {
        lex_print_general_structure( all_args );
        return LEXERROR;
    }

    // initialize all commands and options

    for ( i = 0; i < XLEN_ALL_ARGS; i++ ) {
        command_options_vector[i] = 0;
    }

    rndflag = 0;

    dc_disparity_err_th = 0;
    dc_disparity_war_th = 0;
    dc_running_err_th = 0;
    dc_running_war_th = 0;
    ec_disparity_err_th = 0;
    ec_disparity_war_th = 0;
    ec_running_err_th = 0;
    ec_running_war_th = 0;
    start_timestamp = 0;
    end_timestamp = 0;
    state_size = 0;
    architecture = 0;
    logfile_set = 0;
    write_append = 0;
    lexer_log_en = 1;
    log_file = 0;

    for ( i = 1; i < argc; i++ ) {

        recognized = 0;

        // check for buffer overflow

        strncpy( buffer, argv[i], XRNL_MAX_STR_SIZE - 2 );
        if ( strnlen( buffer, XRNL_MAX_STR_SIZE ) > XRNL_MAX_STR_SIZE - 3 ) {

            return LEXERROR;
        }

        for ( j = 0; j < XLEN_ALL_ARGS_UNIQ; j++ ) {

            if ( !strncmp( argv[i], all_args_uniq[j], 48 ) ) {
                recognized = 1;
            }

        }

        if ( recognized == 1 ) {

            if ( arg_type == XARG_NULL ) {

                if ( XRNL_SUCCESS !=
                     convert_str_to_lexconts( current_command, argv[i], &current_option_or_command, &arg_type,
                                              all_args ) ) {

                    return LEXERROR;
                }

                if ( XRNL_SUCCESS !=
                     check_options_of_commands( current_command, current_option_or_command, &current_command,
                                                all_args ) ) {

                    lex_print_general_structure( all_args );

                    return LEXERROR;
                }

                command_options_vector[current_option_or_command]++;

                if ( ( current_command == XE_EXAMPLE ) || ( current_command == XH_HELP )
                     || ( current_command == XS_SCRIPT ) ) {
                    if ( LEXERROR == initialize_log( lexer_log_en, write_append, logfile_set, log_path ) ) {
                        return LEXERROR;
                    }

                }

                if ( ( ( command_options_vector[XDC_PASSWORD_STR] > 0 ) ||
                       ( command_options_vector[XDC_NO_PASSWORD] > 0 ) ||
                       ( command_options_vector[XDC_INIT_FILE] > 0 ) ) &&
                     ( !( ( command_options_vector[XDC_COMPILED_PARAM] > 0 ) ||
                          ( command_options_vector[XDC_ENCODING_PARAM] > 0 ) ) )
                     ) {
                    snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                              "\nlexer error: expect %s or %s before %s %s %s\n",
                              all_args[XDC_COMPILED_PARAM], all_args[XDC_ENCODING_PARAM],
                              all_args[XDC_INIT_FILE], all_args[XDC_NO_PASSWORD],
                              all_args[XDC_PASSWORD_STR] );
                    XLEX_PRINT(  );

                    return LEXERROR;

                }

                if ( ( ( command_options_vector[XEC_PASSWORD_STR] > 0 ) ||
                       ( command_options_vector[XEC_NO_PASSWORD] > 0 ) ||
                       ( command_options_vector[XEC_INIT_FILE] > 0 ) ) &&
                     ( !( ( command_options_vector[XEC_COMPILED_PARAM] > 0 ) ||
                          ( command_options_vector[XEC_ENCODING_PARAM] > 0 ) ) )
                     ) {
                    snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                              "\nlexer error: expect %s or %s before %s %s %s\n",
                              all_args[XEC_COMPILED_PARAM], all_args[XEC_ENCODING_PARAM],
                              all_args[XEC_INIT_FILE], all_args[XEC_NO_PASSWORD],
                              all_args[XEC_PASSWORD_STR] );
                    XLEX_PRINT(  );

                    return LEXERROR;

                }

                if ( ( ( current_command == XE_EXAMPLE ) || ( current_command == XH_HELP )
                       || ( current_command == XS_SCRIPT ) ) && ( argc == ( i + 1 ) ) ) {
                    lex_help_print_commands( current_command, all_args );
                    if ( logfile_set == 1 ) {
                        if ( 0 != fclose( lexer_log.fp ) ) {
                            printf( "lexer error: input output fail\n" );
                        }

                    }

                    return LEXSTOP;
                } else if ( ( current_command == XV_VERSION ) && ( argc == 2 ) ) {
                    if ( logfile_set == 1 ) {
                        if ( 0 != fclose( lexer_log.fp ) ) {
                            printf( "lexer error: input output fail\n" );
                        }

                    }

                    return LEXFORWARD;

                } else if ( ( current_command == XV_VERSION ) && ( argc > 2 ) ) {
                    snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                              "\nlexer error: %s should be the only argument\n", all_args[XV_VERSION] );
                    XLEX_PRINT(  );
                    if ( logfile_set == 1 ) {
                        if ( 0 != fclose( lexer_log.fp ) ) {
                            printf( "lexer error: input output fail\n" );
                        }

                    }

                    return LEXSTOP;
                }

                if ( ( current_option_or_command == XLC_LIB_ERROR_LOG ) ||
                     ( current_option_or_command == XLC_LIB_WARNING_LOG ) ||
                     ( current_option_or_command == XLC_LIB_INFO_LOG ) ||
                     ( current_option_or_command == XLC_LIB_DEBUG_LOG ) ) {
                    log_file = 1;
                }

                if ( ( ( current_option_or_command == XLC_FORCE_APPEND )
                       || ( current_option_or_command == XLC_FORCE_WRITE ) ) && ( log_file == 1 ) ) {
                    snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                              "\nlexer error: expect %s %s option before log files\n",
                              all_args[XLC_FORCE_APPEND], all_args[XLC_FORCE_WRITE] );
                    XLEX_PRINT(  );

                    return LEXERROR;
                }

                if ( current_option_or_command == XLC_FORCE_APPEND ) {
                    write_append = 1;
                } else if ( current_option_or_command == XLC_NO_COMMAND_LINE_LOG ) {
                    lexer_log_en = 0;
                }

            } else {

                // did not get a command

                if ( arg_type == XARG_COMMAND_NAME ) {
                    snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                              "\nlexer error: expect a command after %s\n",
                              all_args[current_option_or_command] );
                    XLEX_PRINT(  );

                    return LEXERROR;
                } else if ( arg_type == XARG_PATH_R ) {
                    snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                              "\nlexer error: expect an input file path after %s\n",
                              all_args[current_option_or_command] );
                    XLEX_PRINT(  );

                    return LEXERROR;
                } else if ( arg_type == XARG_PATH_W ) {
                    snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                              "\nlexer error: expect an output file path after %s\n",
                              all_args[current_option_or_command] );
                    XLEX_PRINT(  );

                    return LEXERROR;
                } else if ( arg_type == XARG_FLOAT ) {
                    snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                              "\nlexer error: expect a float after %s\n",
                              all_args[current_option_or_command] );
                    XLEX_PRINT(  );

                    return LEXERROR;
                } else if ( arg_type == XARG_INT ) {
                    snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                              "\nlexer error: expect an integer after %s\n",
                              all_args[current_option_or_command] );
                    XLEX_PRINT(  );

                    return LEXERROR;
                } else if ( arg_type == XARG_STR ) {
                    snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                              "\nlexer error: expect a string after %s\n",
                              all_args[current_option_or_command] );
                    XLEX_PRINT(  );

                    return LEXERROR;
                }

            }

            // the "-rnd" option is only a lexer option
        } else if ( !strncmp( "-rnd", argv[i], 6 ) ) {

            if ( ( current_command == XE_EXAMPLE ) || ( current_command == XS_SCRIPT ) ) {
                rndflag = 1;
            } else {
                snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                          "\nlexer error: the -rnd option can be specified only for %s %s commands\n",
                          all_args[XE_EXAMPLE], all_args[XS_SCRIPT] );
                XLEX_PRINT(  );
                lex_print_general_structure( all_args );

                return LEXERROR;
            }

        } else {

            // if the fisrt argument is not recognized
            if ( i == 1 ) {
                lex_print_general_structure( all_args );

                return LEXERROR;
            }

            if ( arg_type == XARG_NULL ) {
                snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                          "\nlexer error: argument %s has not been recognized\n", argv[i] );
                XLEX_PRINT(  );

                return LEXERROR;

                // parse arg command
            } else if ( arg_type == XARG_COMMAND_NAME ) {

                if ( XRNL_SUCCESS !=
                     lex_convert_command_to_int( current_command, argv[i], &commandarg, all_args ) ) {
                    lex_print_general_structure( all_args );
                    if ( logfile_set == 1 ) {
                        if ( 0 != fclose( lexer_log.fp ) ) {
                            printf( "lexer error: input output fail\n" );
                        }

                    }

                    return LEXERROR;
                }

                if ( current_command == XS_SCRIPT ) {
                    lexscripts_all( commandarg, rndflag, all_args );
                    if ( logfile_set == 1 ) {
                        if ( 0 != fclose( lexer_log.fp ) ) {
                            printf( "lexer error: input output fail\n" );
                        }

                    }

                    return LEXSTOP;
                }

                if ( current_command == XE_EXAMPLE ) {

                    lexexamples_all( commandarg, rndflag, all_args );
                    if ( logfile_set == 1 ) {
                        if ( 0 != fclose( lexer_log.fp ) ) {
                            printf( "lexer error: input output fail\n" );
                        }

                    }

                    return LEXSTOP;
                }

                if ( current_command == XH_HELP ) {
                    lexhelp_all( commandarg, all_args );
                    if ( logfile_set == 1 ) {
                        if ( 0 != fclose( lexer_log.fp ) ) {
                            printf( "lexer error: input output fail\n" );
                        }

                    }

                    return LEXSTOP;
                }

                // parse arg paths
            } else if ( arg_type == XARG_PATH_W ) {

                if ( current_option_or_command == XLC_COMMAND_LINE_LOG ) {
                    strncpy( log_path, argv[i], XRNL_MAX_STR_SIZE - 1 );
                    logfile_set = 1;
                }

            } else if ( arg_type == XARG_PATH_R ) {

                // parse arg float
            } else if ( arg_type == XARG_FLOAT ) {

                // Initialize errno to check for errors
                errno = 0;

                numberf = strtof( argv[i], &endptr );

                // Check for errors
                if ( ( errno == ERANGE && ( numberf == FLT_MAX || numberf == -FLT_MAX ) ) ||
                     ( errno != 0 && numberf == 0 ) ) {
                    snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                              "\nlexer error: in parsing the float %s\n", argv[i] );
                    XLEX_PRINT(  );

                    return LEXERROR;
                }

                // Check if the conversion was successful
                if ( endptr == argv[i] ) {
                    snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                              "\nlexer error: No digits found in the input %s.\n", argv[i] );
                    XLEX_PRINT(  );

                    return LEXERROR;
                }

                if ( current_option_or_command == XMXCR_PROB_ONES ) {

                    if ( ( numberf < 0.001 ) || ( numberf > 0.5 ) ) {
                        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                                  "\nlexer error: the float value for %s should be between 0.001 and 0.5\n",
                                  all_args[XMXCR_PROB_ONES] );
                        XLEX_PRINT(  );

                        return LEXERROR;
                    }

                }

                // parse arg int
            } else if ( arg_type == XARG_INT ) {

                numberi = ( uint64_t ) strtoll( argv[i], &endptr, 10 );

                // Check for errors
                if ( ( errno == ERANGE && ( numberi == LLONG_MAX || numberi == -LLONG_MAX ) ) ||
                     ( errno != 0 && numberi == 0 ) ) {
                    snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                              "\nlexer error: in parsing the integer %s\n", argv[i] );
                    XLEX_PRINT(  );

                    return LEXERROR;
                }

                // Check if the conversion was successful
                if ( endptr == argv[i] ) {
                    snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                              "\nlexer error: No digits found in the input %s.\n", argv[i] );
                    XLEX_PRINT(  );

                    return LEXERROR;
                }

                if ( current_option_or_command == XDC_RUNNING_ERR_TH ) {
                    if ( ( numberi < 27 ) || ( numberi > 45 ) ) {
                        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                                  "\nlexer error: expected number in range 27 to 45 for %s.\n",
                                  all_args[XDC_RUNNING_ERR_TH] );
                        XLEX_PRINT(  );

                        return LEXERROR;
                    }

                    dc_running_err_th = numberi;
                } else if ( current_option_or_command == XDC_RUNNING_WAR_TH ) {
                    if ( ( numberi < 24 ) || ( numberi > 40 ) ) {
                        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                                  "\nlexer error: expected number in range 27 to 45 for %s.\n",
                                  all_args[XDC_RUNNING_WAR_TH] );
                        XLEX_PRINT(  );

                        return LEXERROR;
                    }

                    dc_running_war_th = numberi;
                } else if ( current_option_or_command == XDC_DISPARITY_ERR_TH ) {
                    if ( ( numberi < 480 ) || ( numberi > 800 ) ) {
                        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                                  "\nlexer error: expected number in range 27 to 45 for %s.\n",
                                  all_args[XDC_DISPARITY_ERR_TH] );
                        XLEX_PRINT(  );

                        return LEXERROR;
                    }

                    dc_disparity_err_th = numberi;
                } else if ( current_option_or_command == XDC_DISPARITY_WAR_TH ) {
                    if ( ( numberi < 528 ) || ( numberi > 880 ) ) {
                        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                                  "\nlexer error: expected number in range 27 to 45 for %s.\n",
                                  all_args[XDC_DISPARITY_ERR_TH] );
                        XLEX_PRINT(  );

                        return LEXERROR;
                    }

                    dc_disparity_war_th = numberi;
                } else if ( current_option_or_command == XEC_RUNNING_ERR_TH ) {
                    if ( ( numberi < 27 ) || ( numberi > 45 ) ) {
                        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                                  "\nlexer error: expected number in range 27 to 45 for %s.\n",
                                  all_args[XEC_RUNNING_ERR_TH] );
                        XLEX_PRINT(  );

                        return LEXERROR;
                    }

                    ec_running_err_th = numberi;
                } else if ( current_option_or_command == XEC_RUNNING_WAR_TH ) {
                    if ( ( numberi < 24 ) || ( numberi > 40 ) ) {
                        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                                  "\nlexer error: expected number in range 27 to 45 for %s.\n",
                                  all_args[XEC_RUNNING_WAR_TH] );
                        XLEX_PRINT(  );

                        return LEXERROR;
                    }

                    ec_running_war_th = numberi;
                } else if ( current_option_or_command == XEC_DISPARITY_ERR_TH ) {
                    if ( ( numberi < 480 ) || ( numberi > 800 ) ) {
                        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                                  "\nlexer error: expected number in range 27 to 45 for %s.\n",
                                  all_args[XEC_DISPARITY_ERR_TH] );
                        XLEX_PRINT(  );

                        return LEXERROR;
                    }

                    ec_disparity_err_th = numberi;
                } else if ( current_option_or_command == XEC_DISPARITY_WAR_TH ) {
                    if ( ( numberi < 528 ) || ( numberi > 880 ) ) {
                        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                                  "\nlexer error: expected number in range 27 to 45 for %s.\n",
                                  all_args[XEC_DISPARITY_ERR_TH] );
                        XLEX_PRINT(  );

                        return LEXERROR;
                    }

                    ec_disparity_war_th = numberi;
                } else if ( ( current_option_or_command == XMXCR_MAX_TRIES )
                            || ( current_option_or_command == XMXCO_MAX_TRIES ) ) {
                    if ( ( numberi < 1000 ) || ( numberi > 100000 ) ) {
                        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                                  "\nlexer error: expected number in range 1000 to 100000 for %s.\n",
                                  all_args[XMXCO_MAX_TRIES] );
                        XLEX_PRINT(  );

                        return LEXERROR;
                    }

                } else if ( ( current_option_or_command == XMMK_START_TIMESTAMP )
                            || ( current_option_or_command == XMCS_START_TIMESTAMP )
                            || ( current_option_or_command == XMCA_START_TIMESTAMP ) ) {

                    start_timestamp = numberi;

                } else if ( ( current_option_or_command == XMMK_END_TIMESTAMP )
                            || ( current_option_or_command == XMCS_END_TIMESTAMP )
                            || ( current_option_or_command == XMCA_END_TIMESTAMP ) ) {

                    end_timestamp = numberi;
                } else if ( current_option_or_command == XAC_STATE_SIZE ) {
                    if ( numberi < 4 ) {
                        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                                  "\nlexer error: the %s should be greater than 4\n",
                                  all_args[XAC_STATE_SIZE] );
                        XLEX_PRINT(  );

                        return LEXERROR;
                    }

                    state_size = numberi;
                } else if ( current_option_or_command == XAC_CRC_BITS ) {
                    if ( ( numberi != 8 ) && ( numberi != 16 ) && ( numberi != 32 ) && ( numberi != 64 ) ) {
                        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                                  "\nlexer error: the %s should be either 8 16 32 or 64\n",
                                  all_args[XAC_CRC_BITS] );
                        XLEX_PRINT(  );

                        return LEXERROR;
                    }

                } else if ( current_option_or_command == XPC_ARCH ) {
                    if ( ( numberi != 128 ) && ( numberi != 256 ) ) {
                        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                                  "\nlexer error: the %s should be either 128 or 256\n", all_args[XPC_ARCH] );
                        XLEX_PRINT(  );

                        return LEXERROR;
                    }

                    architecture = numberi;
                }

                // parse arg str
            } else if ( arg_type == XARG_STR ) {
                if ( ( current_option_or_command == XDC_PASSWORD_STR )
                     || ( current_option_or_command == XEC_PASSWORD_STR ) ) {

                    // The password size is defined in XRN_ENC_PASS_BUFF_SIZE in xrn_encoder.h
                    strncpy( buffer, argv[i], 256 );
                    len = ( uint64_t ) strnlen( buffer, 256 );
                    if ( len > 256 - 1 ) {
                        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                                  "\nlexer error: string too large %s, maximum 256 characters\n", argv[i] );
                        XLEX_PRINT(  );

                        return LEXERROR;
                    } else if ( len < 10 ) {
                        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                                  "\nlexer error: string too short %s, minimum 10 characters\n", argv[i] );
                        XLEX_PRINT(  );

                        return LEXERROR;
                    }

                    if ( XRNL_SUCCESS != is_valid_password( buffer ) ) {

                        return LEXERROR;
                    }

                } else if ( current_option_or_command == XAC_RND_STR ) {

                    // The password size is defined in XRN_BUFF_SIZE in xrn_encoder.h
                    strncpy( buffer, argv[i], 256 );
                    if ( strnlen( buffer, 256 ) > 256 - 1 ) {

                        return LEXERROR;
                    }

                } else if ( ( current_option_or_command == XMCS_SUBJECT_STR )
                            || ( current_option_or_command == XMCA_SUBJECT_STR ) ) {

                    // The password size is defined in XRN_SUBJECT_CERTIFICATE_LENGTH in xrn_common.h
                    strncpy( buffer, argv[i], 512 );
                    if ( strnlen( buffer, 512 ) > 512 - 1 ) {

                        return LEXERROR;
                    }

                }

            }

            arg_type = XARG_NULL;

        }

    }

    // do logging
    if ( LEXERROR == initialize_log( lexer_log_en, write_append, logfile_set, log_path ) ) {
        return LEXERROR;
    }

    // perform size checks
    if ( ( architecture <= state_size ) && ( architecture != 0 ) && ( state_size != 0 ) ) {
        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                  "\nlexer error: the %s %ld should be > than %s %ld\n", all_args[XPC_ARCH], architecture,
                  all_args[XAC_STATE_SIZE], state_size );
        XLEX_PRINT(  );
        if ( logfile_set == 1 ) {
            if ( 0 != fclose( lexer_log.fp ) ) {
                printf( "lexer error: input output fail\n" );
            }

        }

        return LEXERROR;
    }

    if ( ( dc_running_err_th < dc_running_war_th ) && ( dc_running_err_th != 0 )
         && ( dc_running_war_th != 0 ) ) {
        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                  "\nlexer error: the %s %ld should be >= than %s %ld\n", all_args[XDC_RUNNING_ERR_TH],
                  dc_running_err_th, all_args[XDC_RUNNING_WAR_TH], dc_running_war_th );
        XLEX_PRINT(  );
        if ( logfile_set == 1 ) {
            if ( 0 != fclose( lexer_log.fp ) ) {
                printf( "lexer error: input output fail\n" );
            }

        }

        return LEXERROR;
    }

    if ( ( dc_disparity_err_th < dc_disparity_war_th ) && ( dc_disparity_err_th != 0 )
         && ( dc_disparity_war_th != 0 ) ) {
        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                  "\nlexer error: the %s %ld should be >= than %s %ld\n", all_args[XDC_DISPARITY_ERR_TH],
                  dc_disparity_err_th, all_args[XDC_DISPARITY_WAR_TH], dc_disparity_war_th );
        XLEX_PRINT(  );
        if ( logfile_set == 1 ) {
            if ( 0 != fclose( lexer_log.fp ) ) {
                printf( "lexer error: input output fail\n" );
            }

        }

        return LEXERROR;
    }

    if ( ( ec_running_err_th < ec_running_war_th ) && ( ec_running_err_th != 0 )
         && ( ec_running_war_th != 0 ) ) {
        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                  "\nlexer error: the %s %ld should be >= than %s %ld\n", all_args[XEC_RUNNING_ERR_TH],
                  ec_running_err_th, all_args[XEC_RUNNING_WAR_TH], ec_running_war_th );
        XLEX_PRINT(  );
        if ( logfile_set == 1 ) {
            if ( 0 != fclose( lexer_log.fp ) ) {
                printf( "lexer error: input output fail\n" );
            }

        }

        return LEXERROR;
    }

    if ( ( ec_disparity_err_th < ec_disparity_war_th ) && ( ec_disparity_err_th != 0 )
         && ( ec_disparity_war_th != 0 ) ) {
        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                  "\nlexer error: the %s %ld should be <= than %s %ld\n", all_args[XEC_DISPARITY_ERR_TH],
                  ec_disparity_err_th, all_args[XEC_DISPARITY_WAR_TH], ec_disparity_war_th );
        XLEX_PRINT(  );
        if ( logfile_set == 1 ) {
            if ( 0 != fclose( lexer_log.fp ) ) {
                printf( "lexer error: input output fail\n" );
            }

        }

        return LEXERROR;
    }

    if ( ( start_timestamp > end_timestamp ) && ( start_timestamp != 0 ) && ( end_timestamp != 0 ) ) {
        snprintf( lexer_log.buffer, BUFF_PRINT_SIZE,
                  "\nlexer error: the %s %ld should be <= than %s %ld\n", all_args[XMMK_START_TIMESTAMP],
                  start_timestamp, all_args[XMMK_END_TIMESTAMP], end_timestamp );
        XLEX_PRINT(  );
        if ( logfile_set == 1 ) {
            if ( 0 != fclose( lexer_log.fp ) ) {
                printf( "lexer error: input output fail\n" );
            }

        }

        return LEXERROR;
    }

    ret = lexcheck_all( command_options_vector, all_args );
    if ( XRNL_ERROR_NO_CMD == ret ) {
        if ( logfile_set == 1 ) {
            if ( 0 != fclose( lexer_log.fp ) ) {
                printf( "lexer error: input output fail\n" );
            }

        }

        return LEXERROR;
    } else if ( XRNL_SUCCESS != ret ) {
        lex_print_suggestions( current_command, all_args );
        if ( logfile_set == 1 ) {
            if ( 0 != fclose( lexer_log.fp ) ) {
                printf( "lexer error: input output fail\n" );
            }

        }

        return LEXERROR;
    } else {
#if XCOMPILELEXERONLY == 1
        printf( "correct arguments\n" );
#endif
    }

    return LEXFORWARD;

}

